package com.hrpc.spi;

import com.hrpc.config.ObjectWrapper;
import com.hrpc.loadbalancer.LoadBalancer;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 实现一个简易版本的SPI
 */
public class SpiHandler {
    //定义一个basePath
    private static final String BASE_PATH="META-INF/services";

    //先定义一个缓存，用来保存SPI相关的原始内容
    //静态方法给静态变量赋值，在类加载时优先执行
    private static final Map<String, List<String>> SPI_CONTENT=new ConcurrentHashMap<>(8);
    //缓存每一个接口所对应的实现的实例
    private static final Map<Class<?>,List<ObjectWrapper<?>>> SPI_IMPLMENT=new ConcurrentHashMap<>(32);

    //加载当前类之后需要将SPI信息进行保存，避免运行时频繁执行IO
    static {
        //TODO 怎么加载当前工程和jar包中的classPath的资源
        ClassLoader classLoader=Thread.currentThread().getContextClassLoader();
        URL resource = classLoader.getResource(BASE_PATH);
        if (resource != null){
            File file=new File(resource.getPath());
            File[] files = file.listFiles();
            if (files!=null && files.length > 0){
                for (File child : files) {
                    String name = child.getName();
                    List<String> value=getImplNames(child);
                    SPI_CONTENT.put(name,value);
                }
            }
            System.out.println();
        }
    }

    /**
     * 获取文件的所有实现类名称
     * @param child 文件对象
     * @return 实现类的全限定名称集合
     */
    private static List<String> getImplNames(File child) {
        try(FileReader fileReader=new FileReader(child);
            BufferedReader bufferedReader=new BufferedReader(fileReader)
        ) {
            List<String> implNames=new ArrayList<>();
            while (true){
                String line = bufferedReader.readLine();
                    if (line == null || "".equals(line)){
                    break;
                }
                implNames.add(line);
            }
            return implNames;
        } catch (Exception e) {
            throw new RuntimeException("读取SPI文件时发生异常！！！");
        }
    }
    /**
     * 返回第一个和当前服务相关的实例
     * @param clazz 一个服务接口的class实例
     * @return 第一个实现类的实例
     * @param <T>
     */
    public static <T> ObjectWrapper<T> get(Class<?> clazz) {
        //1.优先走缓存
        List<ObjectWrapper<?>> objects = SPI_IMPLMENT.get(clazz);
        if (objects!=null && objects.size()>0){
            return (ObjectWrapper<T>) objects.get(0);
        }
        buildCache(clazz);
        List<ObjectWrapper<?>> result = SPI_IMPLMENT.get(clazz);
        if (result==null || result.size()==0){
            return null;
        }
        return (ObjectWrapper<T>) result.get(0);
    }

    /**
     * 返回所有和当前服务相关的实例
     * @param clazz 一个服务接口的class实例
     * @return 实现类的实例集合
     * @param <T>
     */
    public synchronized static <T> List<ObjectWrapper<T>> getList(Class<?> clazz) {
        //1.优先走缓存
        List<ObjectWrapper<?>> objects = SPI_IMPLMENT.get(clazz);
        if (objects!=null && objects.size()>0){
            return objects.stream().map(objectWrapper -> (ObjectWrapper<T>) objectWrapper).collect(Collectors.toList());
        }
        //2.构建缓存
        buildCache(clazz);
        //3.再次获取
        List<ObjectWrapper<?>> objectWrappers = SPI_IMPLMENT.get(clazz);
        if (objectWrappers!=null && objectWrappers.size()!=0){
            return objectWrappers.stream().map(objectWrapper -> (ObjectWrapper<T>)objectWrapper).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    /**
     * 构建Clazz相关的缓存
     * @param clazz
     * @return
     */
    private static void buildCache(Class<?> clazz) {
        //1.通过clazz获取与之匹配的实现名称
        String name = clazz.getName();
        List<String> implNames = SPI_CONTENT.get(name);
        if (implNames==null || implNames.size()==0){
            return;
        }
        //2.实例化所有的实现
        List<ObjectWrapper<?>> impls=new ArrayList<>();
        for (String impl : implNames) {
            try {
                //首先进行分割
                String[] codeAndTypeAndName = impl.split("-");
                if (codeAndTypeAndName.length!=3){
                    throw new RuntimeException("SPI长度错误！！！");
                }
                Byte code = Byte.valueOf(codeAndTypeAndName[0]);
                String type=codeAndTypeAndName[1];
                String implName=codeAndTypeAndName[2];
                //反射
                Class<?> aClass = Class.forName(implName);
                //只支持无参构造，去构建一个实例
                Object instance = aClass.getConstructor().newInstance();
                ObjectWrapper<?> objectWrapper=new ObjectWrapper<>(code,type,instance);
                impls.add(objectWrapper);
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException |
                     InvocationTargetException | NoSuchMethodException e) {
                throw new RuntimeException(e);
            }
        }
        SPI_IMPLMENT.put(clazz,impls);
    }

    public static void main(String[] args) {

    }
}
